/*
 * 文件名：RingBuffer.java
 * 描述： RingBuffer.java
 * 修改人：Lo&Wang
 * 修改时间：2016年11月28日
 * 修改内容：新增
 */
package com.lowang.test.thread;

import java.io.Serializable;
import java.lang.reflect.Array;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author zhengmo
 */
public class RingBuffer<T> implements Serializable {
    /** 
     *  
     */
    private static final long serialVersionUID = 6976960108708949038L;
    private volatile AtomicInteger head;
    private volatile AtomicInteger tail;
    private int length;
    final T EMPTY = null;
    private volatile T[] queue;
    public RingBuffer(Class<T> type, int length) {
        this.head = new AtomicInteger(0);
        this.tail = new AtomicInteger(0);
        this.length = length == 0 ? 2 << 16 : length; // 默认2^16  
        this.queue = (T[]) Array.newInstance(type, this.length);
    }
    public void enQueue(T t) {
        if (t == null)
            t = (T) new Object();
        // 阻塞 -- 避免多生成者循环生产同一个节点  
        while (this.tail.get() - this.head.get() >= this.length);
        int ctail = this.tail.getAndIncrement();
        while (this.queue[this.getTail(ctail)] != EMPTY); // 自旋  
        this.queue[this.getTail(ctail)] = t;
        //System.out.println("thread:"+Thread.currentThread().getName());
    }
    public T deQueue() {
        T t = null;
        // 阻塞 -- 避免多消费者循环消费同一个节点  
        while (this.head.get() >= this.tail.get());
        int chead = this.head.getAndIncrement();
        while (this.queue[this.getHead(chead)] == EMPTY); // 自旋  
        t = this.queue[this.getHead(chead)];
        this.queue[this.getHead(chead)] = EMPTY;
        return t;
    }
    public int getHead(int index) {
        return index & (this.length - 1);
        //return index % this.length;
    }
    public int getTail(int index) {
        return index & (this.length - 1);
        //return index % this.length;
    }
    public int getHead() {
        return head.get() & (this.length - 1);
        //return head.get() % (this.length);
    }
    public int getTail() {
        return tail.get() & (this.length - 1);
        //return tail.get() % (this.length );
    }
    public T[] getQueue() {
        return queue;
    }
    public int getLength() {
        return length;
    }
    public void setLength(int length) {
        this.length = length;
    }
}
